package cate.game.activity.newherotrial;

import cate.common.table.activity.herotrial.HeroTrialBaseRow;
import cate.common.table.activity.herotrial.HeroTrialLevelRow;
import cate.common.table.activity.herotrial.HeroTrialOptionHeroRow;
import cate.common.table.d.GDFight;
import cate.common.table.d.GDFunc;
import cate.common.table.d.GDHeroTrial;
import cate.common.table.d.GDOperation;
import cate.common.table.pay.PayItemRow;
import cate.common.util.GameResult;
import cate.game.activity.base.core.RoleFarmActivitySingle;
import cate.game.activity.newherotrial.data.HeroTrialLevel;
import cate.game.activity.newherotrial.msg.HeroTrialLevelResp;
import cate.game.activity.newherotrial.msg.HeroTrialOptionHeroResp;
import cate.game.activity.newherotrial.msg.HeroTrialResp;
import cate.game.play.part.BattleHero;
import cate.game.play.part.FightSide;
import cate.game.play.part.PlaySide;
import cate.game.play.proce.play.PlayPO;
import cate.game.res.MixRes;
import cate.game.res.MixResAdder;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import cate.game.role.bag.hero.Hero;
import cate.game.role.fight.HeroGrid;
import cate.game.role.fight.Position;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.*;

@NoteClass("新英雄试炼")
public class HeroTrialActivity extends RoleFarmActivitySingle {

    @NoteField("通过的关卡")
    public int passLevel;

    @NoteField("关卡数据")
    public Map<Integer, HeroTrialLevel> levels;

    @NoteField("已解锁的关卡")
    public Set<Integer> unLockLevel;


    @NoteField("已挑战通过的关卡id（1-20）")
    public Set<Integer> passLevels;

    @NoteField("当前关卡的候选英雄")
    @Transient
    private List<BattleHero> optionHeros = new ArrayList<>();

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (levels == null) {
            levels = new HashMap<>();
        }
        if (unLockLevel == null) {
            unLockLevel = new HashSet<>();
        }
        if (passLevels == null) {
            passLevels = new HashSet<>();
        }
    }

    @Override
    public void onRoleOpen() {

    }

    @Override
    public void onRoleEnd() {
        passLevel = 0;
        levels.clear();
        optionHeros.clear();
        passLevels.clear();
    }

    @Override
    public void initSend() {
        noticeUpdate();
    }

    @Override
    public void excelCheck() {
        if (!enable()) {
            levels.clear();
            optionHeros.clear();
            return;
        }
        if (optionHeros.isEmpty()) {
            buildOptionHero(1);
        }
        checkOpenLevel();
    }

    private void checkOpenLevel() {
        int day = getCurrentDay();
        for (HeroTrialLevelRow row : role.getGame().table.heroTrial.level.getList()) {
            if (row.levelGroup == showBaseRow().levelGroup && row.openDay <= day) {
                unLockLevel.add(row.levelTid);
            }
        }
    }

    @Override
    public void onDaySpan(boolean silence) {
        super.onDaySpan(silence);
        if (enable()) {
            checkOpenLevel();
        }
    }

    @Override
    public void onEnter() {
        super.onEnter();
        if(enable()){
            if (optionHeros.isEmpty()) {
                buildOptionHero(1);
            }
            role.getFight().removeFuncPosition(funcId());
        }
    }

    public void buildOptionHero(int trialId) {
        optionHeros.clear();
        HeroTrialLevelRow levelRow = nextLevelRow(trialId);
        if (levelRow == null) {
            return;
        }
        for (HeroTrialOptionHeroRow heroRow : role.getGame().table.heroTrial.hero.getList()) {
            if (heroRow.group == levelRow.heroGroup) {
                int heroTid = heroRow.protoId + game().table.dynIns.star.getOffSet(levelRow.heroLevel);
                BattleHero battleHero = role.getGame().fight.hero.buildByDynCfg(null, heroTid, levelRow.heroLevel);
                if (battleHero != null) {
                    optionHeros.add(battleHero);
                }
            }
        }
    }



    private HeroTrialLevelRow nextLevelRow(int trialId) {
        /*HeroTrialBaseRow baseRow = showBaseRow();
        if (baseRow == null) {
            return null;
        }
        final int tarLevel = passLevel + 1;
        int tarDifficulty = 0;
        HeroTrialLevel level = levels.get(tarLevel);
        if (level == null) {
            tarDifficulty = GDHeroTrial.INIT_DIFFICULTY;
        } else {
            tarDifficulty = level.passDifficulty + 1;
        }
        return role.getGame().table.heroTrial.level.findRow(baseRow.levelGroup, tarLevel, tarDifficulty);*/
        HeroTrialBaseRow baseRow = showBaseRow();
        if (baseRow == null) {
            return null;
        }
        return role.getGame().table.heroTrial.level.get(trialId);

    }

    private HeroTrialBaseRow showBaseRow() {
        return role.getGame().table.heroTrial.base.get(configTid());
    }

    @Override
    public int getFightFuncId() {
        return GDFunc.NEW_HERO_TRIAL;
    }

    public GameResult<HeroTrialActivity> showOptionHero(int trialId) {
        GameResult<HeroTrialActivity> r = new GameResult<>();
        buildOptionHero(trialId);
        if (optionHeros.isEmpty()) {
            return r.fail("关卡不存在");
        }
        role.sendNow(new HeroTrialOptionHeroResp(funcId(), optionHeros, trialId));
        return r;
    }

    public GameResult<HeroTrialActivity> startFight(int trialId) {
        GameResult<HeroTrialActivity> r = new GameResult<>();
        if(isFighting()){
            return r.fail("当前正在战斗中");
        }
        HeroTrialLevelRow nextRow = nextLevelRow(trialId);
        if (nextRow == null) {
            return r.fail("关卡不存在");
        }
        if (!unLockLevel.contains(nextRow.levelTid)) {
            return r.fail("关卡尚未解锁");
        } else {
            HeroTrialLevel levelNow = levels.get(nextRow.levelTid);
            if (levelNow == null ) {
                if(nextRow.difficulty > 1) {
                    return r.fail("通关前一关难度才可挑战");
                }
            } else {
                if(nextRow.difficulty - levelNow.passDifficulty > 1) {
                    return r.fail("通关前一关难度才可挑战");
                }
            }
            if (nextRow.levelTid > 1) {
                HeroTrialLevel level = levels.get(nextRow.levelTid - 1);
                HeroTrialLevelRow row = role.getGame().table.heroTrial.level
                        .findRow(nextRow.levelGroup, nextRow.levelTid-1, level.passDifficulty+1);
                if (row != null) {
                    return r.fail("通关前一关卡所有难度才可挑战");
                }

            }

        }
        Position position = role.getFight().getPosition(funcId());
        if (position == null) {
            return r.fail("阵法不存在");
        }
        List<Integer> forceHeroList = new ArrayList<>(nextRow.forceHeroList);
        PlaySide ps = new PlaySide();
        ps.snapshot = new RoleSnapshot(role);
        for (HeroGrid grid : position.grids) {
            BattleHero bh = showAidHero(grid.uid);
            if (bh != null) {
                bh.pos = grid.pos;
                bh.origin = grid.origin;
                ps.addHero(bh);
                forceHeroList.removeIf(a -> a == bh.hero.getTpl(role.getGame().fight.getPlayBuildContext()).protoId);
            }
        }
        ps.updatePower();
        //检测英雄
        if(!forceHeroList.isEmpty()){
            return r.fail("未上阵必上英雄");
        }
        //玩家阵容
        FightSide fsA = role.getGame().fight.side.createFightSideByPlaySide(GDFight.Team.A, ps);
        //怪物阵容
        EcResult<FightSide> fsb_r = role.getGame().fight.side.createFightSideByCode(GDFight.Team.B, nextRow.monsterCode);
        if(!fsb_r.ok()){
            return r.fail(fsb_r.message);
        }
        HeroTrialFTC ftc = new HeroTrialFTC(role, getFightFuncId(), nextRow, this);
        ftc.funcId = getFightFuncId();
        EcResult<PlayPO> fight_r = role.getGame().play.startByRole(role, ftc, fsA, fsb_r.data);
        if (!fight_r.ok()) {
            return r.fail(fight_r.message);
        }
        this.startFighting();
        return r;
    }

    private BattleHero showAidHero(String heroUid) {
        for (BattleHero optionHero : optionHeros) {
            if(StringUtils.equals(optionHero.hero.uid, heroUid)){
                return optionHero;
            }
        }
        return null;
    }

    public GameResult<HeroTrialActivity> getFreeRwd(int level, int difficulty) {
        GameResult<HeroTrialActivity> r = new GameResult<>();
        HeroTrialLevel heroTrialLevel = levels.get(level);
        if (heroTrialLevel == null) {
            return r.fail("通关后方可领取");
        }
        if (heroTrialLevel.passDifficulty < difficulty) {
            return r.fail("通关后方可领取");
        }
        HeroTrialLevel.BuyRecord record = heroTrialLevel.getOrBuildRecord(difficulty);
        if (record.gotFree) {
            return r.fail("奖励已领取");
        }
        HeroTrialLevelRow levelRow = role.getGame().table.heroTrial.level.findRow(showBaseRow().levelGroup, level, difficulty);
        if (levelRow == null) {
            return r.fail("配置不存在");
        }
        record.gotFree = true;
        new MixResAdder().setRes(new MixRes(levelRow.freeRwdStr)).setOperation(GDOperation.HERO_TRIAL_FREE_RWD).setDialogReward(true).exe(role);
        role.sendNow(new HeroTrialLevelResp(funcId(),level, heroTrialLevel));
        return r;
    }


    public void noticeUpdate() {
        if (enable()) {
            role.sendNow(new HeroTrialResp(this));
        }
    }

    public HeroTrialLevel showOrBuildLevel(int level) {
        HeroTrialLevel heroTrialLevel = levels.get(level);
        if (heroTrialLevel == null) {
            heroTrialLevel = new HeroTrialLevel();
            heroTrialLevel.initialize();
            levels.put(level, heroTrialLevel);
        }
        return heroTrialLevel;
    }

    @Override
    public GameResult<Void> allowPay(PayItemRow pir) {
        GameResult<Void> r = new GameResult<>();
        HeroTrialLevelRow levelRow = role.getGame().table.heroTrial.level.get(pir.funcSubId);
        if (levelRow == null) {
            return r.fail("配置不存在");
        }
        if(levelRow.levelGroup != showBaseRow().levelGroup){
            return r.fail("配置不匹配");
        }
        if(StringUtils.isNotBlank(levelRow.payCostStr)){
            return r.fail("此商品不支持付费购买");
        }
        HeroTrialLevel heroTrialLevel = levels.get(levelRow.levelTid);
        if (heroTrialLevel == null) {
            return r.fail("通关后方可领取");
        }
        if (heroTrialLevel.passDifficulty < levelRow.difficulty) {
            return r.fail("通关后方可领取");
        }
        HeroTrialLevel.BuyRecord record = heroTrialLevel.getOrBuildRecord(levelRow.difficulty);
        if (record.buyGift) {
            return r.fail("奖励已购买");
        }
        return r.success();
    }

    @Override
    public void onPaySuccess(PayItemRow payItemRow) {
        HeroTrialLevelRow levelRow = role.getGame().table.heroTrial.level.get(payItemRow.funcSubId);
        afterPay(levelRow);
    }

    private void afterPay(HeroTrialLevelRow levelRow){
        HeroTrialLevel heroTrialLevel = levels.get(levelRow.levelTid);
        HeroTrialLevel.BuyRecord record = heroTrialLevel.getOrBuildRecord(levelRow.difficulty);
        record.buyGift = true;
        new MixResAdder()
                .setRes(new MixRes(levelRow.payRwdStr))
                .setOperation(GDOperation.HERO_TRIAL_PAY_RWD)
                .setDialogReward(true)
                .exe(role);
        role.sendNow(new HeroTrialLevelResp(funcId(),levelRow.levelTid, heroTrialLevel));
    }

    public GameResult<HeroTrialActivity> buyItem(int level, int difficulty) {
        GameResult<HeroTrialActivity> r = new GameResult<>();
        HeroTrialLevelRow levelRow = role.getGame().table.heroTrial.level.findRow(showBaseRow().levelGroup, level, difficulty);
        if (levelRow == null) {
            return r.fail("配置不存在");
        }
        HeroTrialLevel heroTrialLevel = levels.get(levelRow.levelTid);
        if (heroTrialLevel == null) {
            return r.fail("通关后方可领取");
        }
        if (heroTrialLevel.passDifficulty < levelRow.difficulty) {
            return r.fail("通关后方可领取");
        }
        HeroTrialLevel.BuyRecord record = heroTrialLevel.getOrBuildRecord(levelRow.difficulty);
        if (record.buyGift) {
            return r.fail("奖励已购买");
        }
        if (!r.ok()) {
            return r;
        }
        if (StringUtils.isBlank(levelRow.payCostStr)) {
            return r.fail("此商品需要付费购买");
        }
        EcResult consume_r = new MixRes(levelRow.payCostStr).consume(role);
        if (!consume_r.ok()) {
            return r.fail(consume_r.message);
        }
        afterPay(levelRow);
        return r;
    }

    @JsonIgnore
    public Hero getAidHero(String heroUid) {
        if (!enable()) {
            return null;
        }
        BattleHero aidHero = showAidHero(heroUid);
        if (aidHero != null) {
            return aidHero.hero.toHero();
        }
        return null;
    }

}
